using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Query;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.Specifications;

namespace CKY.AgentPlatform.Caching
{
    /// <summary>
    /// 缓存仓储装饰器
    /// </summary>
    public class CachedRepository<T> : IRepository<T> where T : class, IEntity
    {
        private readonly IRepository<T> _repository;
        private readonly DistributedCacheService _cacheService;
        private readonly string _entityCachePrefix;

        public CachedRepository(
            IRepository<T> repository,
            DistributedCacheService cacheService)
        {
            _repository = repository;
            _cacheService = cacheService;
            _entityCachePrefix = typeof(T).Name;
        }

        public IQueryable<T> GetQueryable()
        {
            return _repository.GetQueryable();
        }

        public Task<List<T>> GetListAsync(Expression<Func<T, bool>> predicate = null, 
            Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, 
            Func<IQueryable<T>, IIncludableQueryable<T, object>> includeProperties = null, 
            bool enableTracking = true, bool ignoreQueryFilters = false)
        {
            return _repository.GetListAsync(predicate, orderBy, includeProperties, enableTracking, ignoreQueryFilters);
        }

        public async Task<List<T>> GetPagedListAsync(int skipCount, int maxResultCount, 
            string sorting, Expression<Func<T, bool>> predicate = null, 
            Func<IQueryable<T>, IIncludableQueryable<T, object>> includeProperties = null, 
            bool enableTracking = true, bool ignoreQueryFilters = false, CancellationToken cancellationToken = default)
        {
            return await _repository.GetPagedListAsync(skipCount, maxResultCount, sorting, predicate, 
                includeProperties, enableTracking, ignoreQueryFilters, cancellationToken);
        }

        public async Task<T> FirstOrDefaultAsync(Expression<Func<T, bool>> predicate, 
            Func<IQueryable<T>, IIncludableQueryable<T, object>> includeProperties = null, 
            bool enableTracking = true, bool ignoreQueryFilters = false)
        {
            var cacheKey = $"{_entityCachePrefix}:FirstOrDefault:{GetExpressionCacheKey(predicate)}";
            
            return await _cacheService.GetAsync(cacheKey, async () =>
                await _repository.FirstOrDefaultAsync(predicate, includeProperties, enableTracking, ignoreQueryFilters),
                CacheExpiration.Medium);
        }

        public async Task<T> GetAsync(Expression<Func<T, bool>> predicate, 
            Func<IQueryable<T>, IIncludableQueryable<T, object>> includeProperties = null, 
            bool enableTracking = true, bool ignoreQueryFilters = false)
        {
            var cacheKey = $"{_entityCachePrefix}:Get:{GetExpressionCacheKey(predicate)}";
            
            return await _cacheService.GetAsync(cacheKey, async () =>
                await _repository.GetAsync(predicate, includeProperties, enableTracking, ignoreQueryFilters),
                CacheExpiration.Medium);
        }

        public async Task<T> FindAsync(Expression<Func<T, bool>> predicate, 
            Func<IQueryable<T>, IIncludableQueryable<T, object>> includeProperties = null, 
            bool enableTracking = true, bool ignoreQueryFilters = false)
        {
            var cacheKey = $"{_entityCachePrefix}:Find:{GetExpressionCacheKey(predicate)}";
            
            return await _cacheService.GetAsync(cacheKey, async () =>
                await _repository.FindAsync(predicate, includeProperties, enableTracking, ignoreQueryFilters),
                CacheExpiration.Medium);
        }

        public async Task<T> GetAsync(Guid id, bool includeDetails = true, CancellationToken cancellationToken = default)
        {
            var cacheKey = $"{_entityCachePrefix}:{id}";
            
            return await _cacheService.GetAsync(cacheKey, async () =>
                await _repository.GetAsync(id, includeDetails, cancellationToken),
                CacheExpiration.Medium);
        }

        public async Task<List<T>> GetListAsync(bool includeDetails = false, CancellationToken cancellationToken = default)
        {
            var cacheKey = $"{_entityCachePrefix}:List:All";
            
            return await _cacheService.GetAsync(cacheKey, async () =>
                await _repository.GetListAsync(includeDetails, cancellationToken),
                CacheExpiration.Short);
        }

        public async Task<long> GetCountAsync(Expression<Func<T, bool>> predicate = null, CancellationToken cancellationToken = default)
        {
            var cacheKey = $"{_entityCachePrefix}:Count:{GetExpressionCacheKey(predicate)}";
            
            return await _cacheService.GetAsync(cacheKey, async () =>
                await _repository.GetCountAsync(predicate, cancellationToken),
                CacheExpiration.Short);
        }

        public async Task InsertAsync(T entity, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            await _repository.InsertAsync(entity, autoSave, cancellationToken);
            await ClearEntityCacheAsync(entity);
        }

        public async Task UpdateAsync(T entity, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            await _repository.UpdateAsync(entity, autoSave, cancellationToken);
            await ClearEntityCacheAsync(entity);
        }

        public async Task DeleteAsync(T entity, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            await _repository.DeleteAsync(entity, autoSave, cancellationToken);
            await ClearEntityCacheAsync(entity);
        }

        public async Task DeleteManyAsync(IEnumerable<T> entities, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            await _repository.DeleteManyAsync(entities, autoSave, cancellationToken);
            await ClearEntitiesCacheAsync(entities);
        }

        public async Task DeleteAsync(Expression<Func<T, bool>> predicate, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            var entities = await _repository.GetListAsync(predicate);
            await _repository.DeleteAsync(predicate, autoSave, cancellationToken);
            await ClearEntitiesCacheAsync(entities);
        }

        public async Task<int> CountAsync(Expression<Func<T, bool>> predicate = null, CancellationToken cancellationToken = default)
        {
            return (int)await GetCountAsync(predicate, cancellationToken);
        }

        public async Task<bool> AnyAsync(Expression<Func<T, bool>> predicate = null, CancellationToken cancellationToken = default)
        {
            var cacheKey = $"{_entityCachePrefix}:Any:{GetExpressionCacheKey(predicate)}";
            
            return await _cacheService.GetAsync(cacheKey, async () =>
                await _repository.AnyAsync(predicate, cancellationToken),
                CacheExpiration.Short);
        }

        private async Task ClearEntityCacheAsync(T entity)
        {
            var cacheKeys = new List<string>();
            
            if (entity is IEntity<Guid> guidEntity)
            {
                cacheKeys.Add($"{_entityCachePrefix}:{guidEntity.Id}");
            }
            
            cacheKeys.Add($"{_entityCachePrefix}:List:All");
            cacheKeys.Add($"{_entityCachePrefix}:Count");
            cacheKeys.Add($"{_entityCachePrefix}:Any");
            
            foreach (var key in cacheKeys)
            {
                await _cacheService.RemoveAsync(key);
            }
        }

        private async Task ClearEntitiesCacheAsync(IEnumerable<T> entities)
        {
            await _cacheService.RemoveAsync($"{_entityCachePrefix}:List:All");
            await _cacheService.RemoveAsync($"{_entityCachePrefix}:Count");
            await _cacheService.RemoveAsync($"{_entityCachePrefix}:Any");
        }

        private string GetExpressionCacheKey(Expression<Func<T, bool>> predicate)
        {
            if (predicate == null)
                return "null";
            
            // 简化实现，实际项目中可以使用更复杂的表达式序列化
            return predicate.ToString().GetHashCode().ToString();
        }

        // IRepository 接口的其他方法实现
        public IUnitOfWorkManager UnitOfWorkManager => _repository.UnitOfWorkManager;
        public IAbpLazyServiceProvider ServiceProvider => _repository.ServiceProvider;
        public ITypeList<IEntityChangeTrackingContributor> TrackingContributors => _repository.TrackingContributors;
        public IChangeTracker ChangeTracker => _repository.ChangeTracker;

        public DbSet<T> GetDbSet()
        {
            return _repository.GetDbSet();
        }

        public Task EnsureCollectionLoadedAsync<TProperty>(T entity, Expression<Func<T, IEnumerable<TProperty>>> propertyExpression, 
            CancellationToken cancellationToken = default) where TProperty : class
        {
            return _repository.EnsureCollectionLoadedAsync(entity, propertyExpression, cancellationToken);
        }

        public Task EnsurePropertyLoadedAsync<TProperty>(T entity, Expression<Func<T, TProperty>> propertyExpression, 
            CancellationToken cancellationToken = default) where TProperty : class
        {
            return _repository.EnsurePropertyLoadedAsync(entity, propertyExpression, cancellationToken);
        }

        public Task HardDeleteAsync(T entity, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            return _repository.HardDeleteAsync(entity, autoSave, cancellationToken);
        }
    }

    /// <summary>
    /// 缓存仓储工厂
    /// </summary>
    public static class CachedRepositoryFactory
    {
        public static IRepository<T> CreateCachedRepository<T>(
            IRepository<T> repository,
            DistributedCacheService cacheService) where T : class, IEntity
        {
            return new CachedRepository<T>(repository, cacheService);
        }
    }

    /// <summary>
    /// 查询优化器
    /// </summary>
    public static class QueryOptimizer
    {
        /// <summary>
        /// 优化查询：只选择需要的字段
        /// </summary>
        public static IQueryable<T> SelectFields<T>(IQueryable<T> query, params Expression<Func<T, object>>[] selectors)
        {
            return selectors.Aggregate(query, (current, selector) => current.Select(selector).Select(x => x));
        }

        /// <summary>
        /// 优化查询：分页
        /// </summary>
        public static async Task<List<T>> PaginateAsync<T>(
            this IQueryable<T> query,
            int skipCount,
            int maxResultCount,
            CancellationToken cancellationToken = default)
        {
            return await query
                .Skip(skipCount)
                .Take(maxResultCount)
                .ToListAsync(cancellationToken);
        }

        /// <summary>
        /// 优化查询：包含相关实体
        /// </summary>
        public static IQueryable<T> IncludeNavigation<T>(
            this IQueryable<T> query,
            params Expression<Func<T, object>>[] includes) where T : class
        {
            return includes.Aggregate(query, (current, include) => current.Include(include));
        }

        /// <summary>
        /// 优化查询：按条件过滤
        /// </summary>
        public static IQueryable<T> WhereIf<T>(
            this IQueryable<T> query,
            bool condition,
            Expression<Func<T, bool>> predicate)
        {
            return condition ? query.Where(predicate) : query;
        }

        /// <summary>
        /// 优化查询：排序
        /// </summary>
        public static IQueryable<T> OrderByIf<T, TKey>(
            this IQueryable<T> query,
            bool condition,
            Expression<Func<T, TKey>> keySelector,
            bool descending = false)
        {
            if (!condition)
                return query;

            return descending ? query.OrderByDescending(keySelector) : query.OrderBy(keySelector);
        }
    }

    /// <summary>
    /// 数据库查询性能监控
    /// </summary>
    public class QueryPerformanceMonitor : IDisposable
    {
        private readonly string _operationName;
        private readonly ILogger<QueryPerformanceMonitor> _logger;
        private readonly System.Diagnostics.Stopwatch _stopwatch;

        public QueryPerformanceMonitor(string operationName, ILogger<QueryPerformanceMonitor> logger)
        {
            _operationName = operationName;
            _logger = logger;
            _stopwatch = System.Diagnostics.Stopwatch.StartNew();
        }

        public void Dispose()
        {
            _stopwatch.Stop();
            var elapsed = _stopwatch.ElapsedMilliseconds;
            
            if (elapsed > 1000) // 慢查询阈值
            {
                _logger.LogWarning("慢查询检测: {OperationName} 耗时 {ElapsedMs}ms", _operationName, elapsed);
            }
            else
            {
                _logger.LogDebug("查询性能: {OperationName} 耗时 {ElapsedMs}ms", _operationName, elapsed);
            }
        }
    }

    /// <summary>
    /// 查询性能监控扩展
    /// </summary>
    public static class QueryPerformanceExtensions
    {
        public static QueryPerformanceMonitor MonitorQuery(this ILogger logger, string operationName)
        {
            return new QueryPerformanceMonitor(operationName, logger);
        }
    }
}